
/*
socket
bind
listen
accept
send
recv
*/
#include <sys/types.h>
#include <sys/socket.h>
#include <string.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <stdio.h>

#define Server_port 8888
#define BACKLOG 10

int main(int argc, char **argv)
{
  int sock;
  int iRet;
  int isocketclient;
  int addlen;
  int recvlen;
  int iclientnum = 0;
  unsigned char Recbuffer[1000];
  struct sockaddr_in tsocketaddr; // 使用sockaddr这个结构体，命名为tsocketaddr
  struct sockaddr_in tclientaddr; // 使用sockaddr这个结构体，命名为tclientaddr

  // socket创建一个句柄，如果返回值为-1则失败
  sock = socket(AF_INET, SOCK_STREAM, 0); // AF_INET表示ipv4，SOCK_STREAM表示启动tcp连接
  if (-1 == sock)
  {
    printf("socket error\n");
    return -1;
  }

  // 使用sockaddr_in这个结构体，使用bind函数写入服务器的ip端口，与句柄绑定
  tsocketaddr.sin_family = AF_INET;                                                  // ipv4
  tsocketaddr.sin_addr.s_addr = INADDR_ANY;                                          // 本机的所有ip
  tsocketaddr.sin_port = htons(Server_port);                                         // 需要监听的端口host to nets转换成网络信号
  memset(tsocketaddr.sin_zero, 0, 8);                                                // 作用是将某一块内存中的内容全部设置为指定的值，把tsocketaddr.sin_zero的8位置0
  iRet = bind(sock, (const struct sockaddr *)&tsocketaddr, sizeof(struct sockaddr)); // sock为 socket 函数调用返回的文件描述符，使 用 另 外 一 个 结 构 (struct
  // sockaddr_in 来代替，该结构体主要包含ip和端口， sockaddr结构的长度
  // 若bind函数的返回值为-1，则绑定失败
  if (-1 == iRet)
  {
    printf("bind error\n");
    return -1;
  }

  // 使用listen函数开启监听，监听上述服务器绑定的ip与端口，请求排队最大长度为10，若listen函数的返回值为-1，则监听开启失败
  iRet = listen(sock, BACKLOG); // 监听开启

  if (-1 == iRet)
  {
    printf("listen error\n");
    return -1;
  }

  // 使用accept函数获得连接请求，并且建立连接
  while (1)
  {
    addlen = sizeof(struct sockaddr); // 获取struct sockaddr的大小
    isocketclient = accept(sock, (struct sockaddr *)&tclientaddr, &addlen);
    if (-1 != isocketclient)
    { // 成功则打印客户端的地址，inet_ntoa把tclientaddr.sin_addr中的数据读取并转换位acsII码
      iclientnum++;
      printf("get connect from%d%s\n", iclientnum, inet_ntoa(tclientaddr.sin_addr));
    }
    if (!fork())
    {           // 子进程的源码
      while (1) // 复制客户端的数据并且显示
      {
        recvlen = recv(isocketclient, Recbuffer, 999, 0); // 接受最多999位数据
        if (recvlen <= 0)
        {
          printf("recv error"); // 数据小于0时程序错误
        }
        else
        {
          Recbuffer[recvlen] = '\0';
          printf("get mes from%d:%s\n", iclientnum, Recbuffer); // 接受到数据时打印出来
        }
      }
    }
  }

  close(sock);
  return 0;
}